<template>
  <div class="grid-rq" :ref="this.refId+'text'">
    <div v-if="showModal" class="mask">
      <!-- <img class="loading-image" src="../../image/loading.gif" alt="正在处理，请等待。。。">
      <span class="mask-text">处理中，请等待...</span>-->
    </div>
    <div class="grid-title" v-if="gridTitle != null">
      <span>{{gridTitle}}</span>
    </div>
    <el-table v-loading="gridLoading" :data="gridData" :height="gridHeight" :ref="refId" border :highlight-current-row="true" @selection-change="handleSelectionChange"
      @current-change="handleCurrentChange" @sort-change="handleSortChange" @row-click="rowclick" :header-row-class-name="headerRowClassName" :cell-class-name="cellClassName"
      :row-class-name="rowClassName" :header-cell-class-name="headerCellClassName" stripe :row-style="{height:'38px'}" :header-row-style="{height:'38px'}"
      :cell-style="{padding:'2px'}" :header-cell-style="{padding:'2px',fontSize:'12px'}" @keyup.native="handleFilter" :show-summary="showSummary">
      <div v-if="indexNo">
        <el-table-column type="index" label="序号" :fixed="true" align="center" width="65">
        </el-table-column>
      </div>
      <div v-if="createPointNumber">
        <el-table-column type="index" align="center" :fixed="true" width="1">
          <template slot-scope="scope">
            <template>
              <div :id="'point'+scope.row[pointFiled]" class="point-item">
              </div>
            </template>
          </template>
        </el-table-column>
      </div>
      <div v-if="multi">
        <el-table-column v-if="multi" header-align="center" :fixed="false" align="center" type="selection" width="50"></el-table-column>
      </div>
      <div v-for="(cols, index) in columns" :key="index">
        <el-table-column v-if="cols.template" :header-align="cols.headerAlign" :align="cols.align" :formatter="cols.formatter" :sortable="cols.sortable" :prop="cols.prop"
          :type="cols.order" :label="cols.label" :fixed="cols.fixed || false" :width="cols.width" :min-width="cols.minWidth">
          <template slot-scope="scope">
            <template v-if="cols.template == 'img'">
              <div class="img-div">
                <img class="img-bd" v-if="isPro" :src="cols.prefix + scope.row[cols.prop]" width="28" height="28" />
                <div class="img-text">{{scope.row[cols.templateProp]}}</div>
              </div>
            </template>
            <template v-if="cols.template == 'imageBox'">
              <el-image v-for="(image,index) in scope.row[cols.prop]" :key="index" style="width: 30px; height: 30px" :src="image[cols.urlProp]"
                :preview-src-list="[image[cols.urlProp]]">
              </el-image>
            </template>
            <template v-if="cols.template == 'switch'">
              <el-switch v-model="scope.row[cols.prop]" active-color="#13ce66" inactive-color="#ff4949" @change="switchChange(scope.row,scope.row[cols.prop])"></el-switch>
            </template>
            <template v-if="cols.template == 'select'">
              <el-select v-model="scope.row[cols.prop]">
                <el-option v-for="(type,sindex) in cols.selectDatas||[]" :label="type[cols.selectName||'name']" :value="type[cols.selectValue||'value']" :key="sindex">
                </el-option>
              </el-select>
            </template>
            <template v-if="cols.template == 'op'">
              <span class="opBtn" href="#" v-for="(op,index) in cols.opList" :key="index" @click="opClick(scope.row,op.name,op.clickName,op.confirm)" v-if="permissions[op.auth]"
                v-show="opBtnShow(scope.row,scope.row[op.prop],scope.row[op.valueProp],op.showValue,op.showFomatter)" :style="{color:op.btnColor}">{{op.name}}</span>
            </template>
            <template v-if="cols.template == 'btn'">
              <el-button class="Btn-box" href="#" type="primary" v-for="(op,index) in cols.opList" :key="index" @click="opClick(scope.row,op.name,op.clickName,op.confirm)"
                v-if="permissions[op.auth]" v-show="opBtnShow(scope.row,scope.row[op.prop],scope.row[op.valueProp],op.showValue,op.showFomatter)" size="small">{{op.name}}
              </el-button>
            </template>
            <template v-if="cols.template == 'cell'">
              <div class="cell-text">{{scope.row[cols.prop]}}</div>
            </template>
            <template v-if="cols.template == 'number'">
              <div class="cell-text">{{scope.row[cols.prop] | twoNumber}}</div>
            </template>
            <template v-if="cols.template == 'sortStatus'">
              <div v-if="scope.row[cols.prop] >0" style="color:red;">{{scope.row[cols.prop] }}
                <i class="rayicon iconfont icon-jiantou-copy"></i>
              </div>
              <div v-if="scope.row[cols.prop] <0" style="color:green;">{{scope.row[cols.prop] }}
                <i class="rayicon iconfont icon-jiantou"></i>
              </div>
              <div v-if="scope.row[cols.prop] ==0">-</div>
            </template>
            <template v-if="cols.template == 'sortColor'">
              <div v-if="scope.row[cols.prop] >0" style="color:red;">+{{scope.row[cols.prop]*100 | oneNumber }}%</div>
              <div v-if="scope.row[cols.prop] <0" style="color:green;">{{scope.row[cols.prop]*100 | oneNumber }}%</div>
              <div v-if="scope.row[cols.prop] ==0">-</div>
            </template>
            <template v-if="cols.template == 'bgColor'">
              <div :style="{color:bgColor(cols.bgColor,scope.row[cols.prop],scope.row)}">{{bgColorValue(cols.formatter,scope.row[cols.prop],scope.row)}}</div>
            </template>
            <template v-else-if="cols.template == 'edit'">
              <div class="edit-div">
                <el-input :type="scope.row.type ? scope.row.type : 'text'" v-if="scope.row.editable||enableEdit" @blur="doEditAfter(scope.$index,scope.row,cols.prop)"
                  v-model="scope.row[cols.prop]" class="keyNextClass" :class="index+'aa'" @focus="doFocus($event)" @change="editDataChange(scope.row,cols.rowChange)"></el-input>
                <div class="edit-value" @dblclick="editClick(scope.$index,scope.row)" v-if="!(scope.row.editable||enableEdit)">{{scope.row[cols.prop]}}</div>
              </div>
            </template>
          </template>
        </el-table-column>
        <el-table-column v-if="!cols.template" :header-align="cols.headerAlign" :align="cols.align" :formatter="cols.formatter" :sortable="cols.sortable" :prop="cols.prop"
          :type="cols.order" :label="cols.label" :fixed="cols.fixed" :width="cols.width" :min-width="cols.minWidth">
        </el-table-column>
      </div>

    </el-table>
    <div class="grid-pagination" v-if="pagination">
      <el-pagination class="grid-pagination-content" @size-change="handleSizeChange" @current-change="handlePageChange" :current-page="page.currentPage" :page-sizes="pageSizes"
        :page-size="page.pageSize" layout="total, sizes, prev, pager, next, jumper" :total="page.totalCount" :small="false">
      </el-pagination>
    </div>
    <!-- 锚点 跳转 -->
    <div class="grid-point" v-if="showPoint">
      <div class="grid-point-item" v-for="(page, index) in pointEntity.size" :key="index" @click="pointClick(page)">
        {{(page-1)*pointEntity.pageSize+1}}- {{page*pointEntity.pageSize}}
      </div>
    </div>
  </div>
</template>
<script>
import request from '@/router/axios'
import { Message, MessageBox } from 'element-ui'

export default {
  name: 'grid',
  data () {
    return {
      currentEditInput: null,
      changeEditInput: null,
      showModal: false,
      isPro: true,
      gridLoading: false,
      editableStatus: [],
      gridData: [],
      gridHeight: null,
      titleHeight: 40,
      bottomHeight: 40,
      currentRows: null,
      currentRow: null,
      pointEntity: {
        size: 0,
        pageSize: 50,
        loadingPage: 1
      },
      query: {
        text: null,
        entity: {}
      },
      page: {
        pageSize: 0,
        currentPage: 1,
        totalCount: 0,
        orderBy: ''
      }
    }
  },
  filters: {
    oneNumber: function (value) {
      value = Number(value)
      return value.toFixed(1)
    },
    twoNumber: function (value) {
      value = Number(value)
      return value.toFixed(2)
    }
  },
  props: {
    url: {
      type: String,
      default: function () {
        return null
      }
    },
    diffHeight: {
      type: String,
      default: function () {
        return '0'
      }
    },
    headerRowClassName: {
      type: String,
      default: function () {
        return null
      }
    },
    keyEditStep: {
      type: Number,
      default: function () {
        return 1
      }
    },
    pointFiled: {
      type: String,
      default: function () {
        return 'indexSort'
      }
    },
    resultType: {
      type: String,
      default: function () {
        return 'Object'
      }
    },
    gridTitle: {
      type: String,
      default: function () {
        return null
      }
    },
    orderField: {
      type: String,
      default: function () {
        return null
      }
    },
    orderType: {
      type: String,
      default: function () {
        return ' desc '
      }
    },
    refId: {
      type: String,
      default: function () {
        return 'mainGrid'
      }
    },
    height: {
      type: String,
      default: function () {
        return null
      }
    },
    showSummary: {
      type: Boolean,
      default: function () {
        return false
      }
    },
    multi: {
      type: Boolean,
      default: function () {
        return false
      }
    },
    showPoint: {
      type: Boolean,
      default: function () {
        return false
      }
    },
    createPointNumber: {
      type: Boolean,
      default: function () {
        return false
      }
    },
    permissions: {
      type: Object,
      default: function () {
        return {}
      }
    },
    indexNo: {
      type: Boolean,
      default: function () {
        return true
      }
    },
    pageSize: {
      type: Number,
      default: function () {
        return 15
      }
    },
    pageSizes: {
      type: Array,
      default: function () {
        return [10, 15, 20, 50, 100]
      }
    },
    columns: {
      type: Array
    },
    rowClickName: {
      type: String
    },
    rowClassName: {
      type: String,
      default: function () {
        return null
      }
    },
    cellClassName: {
      type: String,
      default: function () {
        return null
      }
    },
    headerCellClassName: {
      type: String,
      default: function () {
        return null
      }
    },
    queryText: {
      type: String
    },
    queryEntity: {
      type: Object
    },
    enableEdit: {
      type: Boolean,
      default: function () {
        return false
      }
    },
    pagination: {
      type: Boolean,
      default: function () {
        return false
      }
    },
    loading: {
      type: Boolean,
      default: function () {
        return true
      }
    }
  },
  created () {
    this.resetDiffHeight(this.diffHeight)
    this.page.pageSize = this.pageSize
    // 获取参数
    this.query.text = this.queryText
    this.query.entity = this.queryEntity
    // 设置排序字段
    if (this.orderField) {
      this.page.orderBy = this.orderField + ' ' + this.orderType
    }
  },
  mounted () {
    if (this.loading) {
      this.query.entity = this.queryEntity
      this.gridQuery()
    }
  },
  methods: {
    doFocus (event) {
      this.currentEditInput = event.target.parentNode
    },
    editDataChange (row, rowChange) {
      this.$emit("editDataChange")
      if (rowChange) {
        this.$emit("rowDataChange", row)
      }
    },
    handleFilter (ev, index) {
      //向上 =38
      if (ev.keyCode == 38) {
        this.changeEditInput = null
        this.doKeyStep(0 - this.keyEditStep)
      }
      //下 = 40
      if (ev.keyCode == 40) {
        this.changeEditInput = null
        this.doKeyStep(this.keyEditStep)
      }
      //左 = 37
      if (ev.keyCode == 37) {
        this.changeEditInput = null
        this.doKeyStep(-1)
      }

      //右 = 39
      if (ev.keyCode == 39) {
        this.changeEditInput = null
        this.doKeyStep(1)
      }

      //回车 = 13
      if (ev.keyCode == 13) {
        this.changeEditInput = null
        this.doKeyStep(this.keyEditStep)
      }
    },
    doKeyStep (step) {
      let editInputs = document.querySelectorAll(".el-table__body-wrapper .keyNextClass")
      let _this = this
      if (this.currentEditInput) {
        editInputs.forEach((inpput, index) => {
          if (inpput === _this.currentEditInput && _this.currentEditInput != _this.changeEditInput) {
            let next = (index + step)
            let nextInput = editInputs[next]
            if (nextInput) {
              _this.changeEditInput = nextInput
              nextInput.querySelector("input").focus()
            }
          }
        })
      }
    },
    gridQuery () {
      this.gridLoading = true
      const data = this.createQueryData()
      this.handlePage(data).then(result => {
        this.gridLoading = false
        if (this.pagination) {
          this.gridData = result.records
          this.page.currentPage = result.current
          this.page.pageSize = result.size
          this.page.totalCount = result.total
          this.initPointToatl(result.total)
        } else {
          this.gridData = result
        }
      })
    },
    initPointToatl (total) {
      this.$emit('totalCallback', total)
      if (total % this.pointEntity.pageSize === 0) {
        this.pointEntity.size = total / this.pointEntity.pageSize
      } else {
        this.pointEntity.size = parseInt(total / this.pointEntity.pageSize) + 1
      }
      this.pointEntity.loadingPage = 1
    },
    handleSortChange (col) {
      let orderType = ''
      if (col.order === 'ascending') {
        orderType = '  asc'
      } else {
        orderType = '  desc'
      }
      if (!col.column || !col.column.type) return
      this.page.orderBy = col.column.type + orderType
      this.gridQuery()
    },
    handleSizeChange (val) {
      this.page.pageSize = val
      this.gridQuery()
    },
    handlePageChange (val) {
      this.page.currentPage = val
      this.gridQuery()
    },
    handleCurrentChange (row) {
      this.currentRow = row
      if (this.multi) {
        this.$refs[this.refId].toggleRowSelection(row);
      }
    },
    handleSelectionChange (rows) {
      this.currentRows = rows
      this.$emit("change", rows)
    },
    rowclick (row, event, col) {
      if (this.rowClickName) {
        this.$emit(this.rowClickName, row, event, col)
      }
    },
    getCurrentRow () {
      if (this.multi) {
        if (this.currentRows && this.currentRows.length == 1) {
          return this.currentRows[0]
        } else {
          return null;
        }
      } else {
        return this.currentRow
      }
    },
    getCurrentRows () {
      return this.currentRows
    },
    getSelectOne () {
      if (this.currentRows.length == 1) {
        return this.currentRows[0]
      } else {
        MessageBox.alert("请选择一行数据");
        return null;
      }
    },
    getData () {
      return this.gridData
    },
    initData (data) {
      this.gridData = data
    },
    getDataKey (prop) {
      const ids = []
      this.gridData.forEach((d, index) => {
        ids.push(d[prop])
      })
      return ids;
    },
    addRow (rowData) {
      this.gridData.push(rowData)
      this.page.totalCount = this.page.totalCount + 1
    },
    setOrderField (orderField, orderType) {
      this.page.orderBy = orderField + ' ' + orderType
    },
    setPageSize (size) {
      this.page.pageSize = size
      this.gridQuery()
    },
    resetDiffHeight (diffHeight) {
      if (this.height === 'auto') {
        this.gridHeight = window.innerHeight - diffHeight - this.titleHeight - 5
        if (this.pagination) {
          this.gridHeight = this.gridHeight - this.bottomHeight - diffHeight
        }
      } else if (this.height.indexOf(':') === 0) {
        const value = parseFloat('0.' + this.height.substring(1))
        this.gridHeight = (window.innerHeight - diffHeight) * value - this.titleHeight - 5
        if (this.pagination) {
          this.gridHeight = this.gridHeight - this.bottomHeight - diffHeight
        }
      } else {
        this.gridHeight = Number(this.height)
      }
    },
    deleteRow (rowData) {
      const index = this.gridData.indexOf(rowData)
      if (index >= 0) {
        this.gridData.splice(index, 1)
        this.page.totalCount = this.page.totalCount - 1
      }
      this.$emit("editDataChange")
    },
    deleteAll () {
      this.gridData = []
      this.$emit("editDataChange")
    },
    createQueryData () {
      let queryData = {
        page: {
          current: this.page.currentPage,
          size: this.page.pageSize,
          orderBy: this.page.orderBy
        },
        query: this.query.text,
        entity: this.query.entity
      }
      if (!this.pagination) {
        queryData = this.query.entity
      }
      return queryData;
    },
    reload () {
      this.gridQuery()
    },
    doQuery (query, entity) {
      this.query.text = query
      this.query.entity = entity || this.queryEntity
      //设置第一页
      this.page.currentPage = 1
      this.gridQuery()
    },
    editClick (index, row) {
      if (!this.enableEdit) {
        this.$set(row, 'editable', true)
        this.$emit('beforeEdit', row)
      }

    },
    doEditAfter (index, row, prop) {
      if (!this.enableEdit) {
        // this.currentEditInput = null
        this.$set(row, 'editable', false)
        this.$emit('afterEdit', row, prop)
      }
    },
    changeEditType (row, type = false) {
      this.$set(row, 'editable', type)
    },
    switchChange (row, value) {
      this.$emit('switch', row, value)
    },
    opClick (row, name, fun, confirm) {
      //this.$emit(name, row)
      let _this = this
      if (confirm) {
        this.$confirm("操作:" + name + ", 是否继续?", "提示", {
          confirmButtonText: "确定",
          cancelButtonText: "取消",
          type: "warning"
        }).then(() => {
          this.showModal = true;
          try {
            this.$emit(fun, row)
          } catch (e) {
            this.showModal = false
          }
          setTimeout(function () {
            _this.showModal = false
          }, 500)
        });
      } else {
        this.$emit(fun, row)
      }
    },
    opBtnShow (row, value, valueProp, valueList, showFomatter) {
      let isShow = true
      if (valueList) {
        if (valueProp != null) {
          isShow = valueList.indexOf(valueProp) >= 0
        } else {
          isShow = valueList.indexOf(value) >= 0
        }
      }
      if (showFomatter) {
        isShow &= showFomatter(row)
      }
      return isShow
    },
    bgColor (colors, key, row) {
      let color = '#000'
      if (colors && key) {
        color = colors[key]
      }
      return color
    },
    bgColorValue (formatter, value, row) {
      if (formatter) {
        return formatter(row, null, value)
      }
      return value
    },
    pointClick (page) {
      // 表示为加载到数据
      const jumpHeight = (page - 1) * this.pointEntity.pageSize * 49
      this.$refs[this.refId + 'text'].querySelector('.el-table__body-wrapper').scrollTop = jumpHeight
    },
    handlePage (data) {
      return request({
        url: this.url,
        method: 'post',
        data
      })
    }
  }
}
</script>

<style lang="scss" scoped>
.grid-title {
  width: 100%;
  height: 40px;
  border: 1px solid rgb(235, 235, 235);
  span {
    height: 35px;
    padding-top: 12px;
    padding-left: 8px;
    float: left;
    font-family: '微软雅黑 Regular', '微软雅黑';
    font-size: 14px;
    color: #a2a2a2;
  }
}

.grid-pagination {
  width: 100%;
  height: 35px;
  border: 1px solid rgb(235, 235, 235);
  background-color: white;
  .grid-pagination-content {
    float: left;
    height: 20px;
    padding-top: 5px;
    padding-left: 15px;
  }
}

.img-div {
  text-align: left;
  margin-left: 15px;
  vertical-align: middle;
  .img-bd {
    float: left;
    margin-right: 3px;
  }
  .img-text {
    float: left;
    height: 28px;
    padding-top: 3px;
  }
}

.edit-div {
  text-align: left;
  margin-left: 15px;
  vertical-align: middle;
  .edit-value {
    width: 80%;
    text-align: center;
  }
}

.cell-text {
  font-family: 'Arial Negreta', 'Arial';
  font-weight: 700;
  font-style: normal;
  color: #4994f1;
}

.rayicon {
  vertical-align: middle;
}

.grid-point {
  position: absolute;
  bottom: 25px;
  right: -45px;
  width: 42px;
  .grid-point-item {
    text-align: center;
    vertical-align: middle;
    padding: 5px auto;
    width: 40px;
    height: 40px;
    border: 1px solid white;
    background-color: #4994f1;
    cursor: pointer;
    font-family: 'Arial Negreta', 'Arial';
    font-weight: 400;
    font-size: 12px;
    font-style: normal;
    color: white;
  }
}

.point-item {
  min-height: 30px;
}

.opBtn {
  cursor: pointer;
  font-weight: 500;
  font-style: normal;
  font-size: 13px;
  color: #4994f1;
  margin: 0px 3px;
}
.Btn-box {
  margin: 2px 3px;
}
.mask {
  background-color: rgb(0, 0, 0);
  opacity: 0.3;
  position: fixed;
  top: 0;
  left: 0;
  width: 100%;
  height: 100%;
  z-index: 9999;
}
.mask-text {
  text-align: center;
  color: #fff;
  width: 160px;
  height: 60px;
  margin: 300px auto;
  position: absolute;
  z-index: 9998;
}
</style>
